//
//  GQJCategoryViewController.m
//  TotalDemo
//
//  Created by gujian on 16/8/24.
//  Copyright © 2016年 gujian. All rights reserved.
//

#import "GQJCategoryViewController.h"
#import <objc/runtime.h>
#import <objc/message.h>
#import "TestCopy.h"
#import "TestCopy+Category1.h"
#import "TestCopy+Category2.h"

NSString * const GQJCategoryNotification = @"GQJCategoryNotification";

@interface GQJCategoryViewController ()
{
    NSString *_str;
}

@property (nonatomic, strong) NSString *str;

@end



@implementation GQJCategoryViewController

@dynamic str;

/**
 *  http://tech.meituan.com/DiveIntoCategory.html
    表明category文件的编译顺序决定了使用中将调用哪一个category方法
    category其实并不是完全替换掉原来类的同名方法，只是category在方法列表的前面
 */
- (void)viewDidLoad {
    [super viewDidLoad];

    self.title = @"探究是否可以调用指定category中的方法";
    
    //可通过在build中改变category文件的编译顺序来决定到底调用哪一个category中的方法
    TestCopy *testCopy = [[TestCopy alloc] init];
//    [testCopy printIdentify];
    
//    [self callTheOriginMethod];
    
    
//    [self callTheMethod:0];
//    [self callTheMethod:1];
//    [self callTheMethod:2];
    
    [self getInstanceSize];
    
//    self.str = @"123"; //此行会崩溃，因为没有get/set方法
    NSLog(@"static instance variable:%@", className);
    
    [self testStaticVariable];
}

//调用原有类的方法
- (void)callTheOriginMethod
{
    
    Class currentClass = [TestCopy class];
    TestCopy *testCopy = [[TestCopy alloc] init];
    
    if (currentClass) {
        
        unsigned int methodCount = 0;
        Method *methodList = class_copyMethodList(currentClass, &methodCount);
        IMP lastImp = NULL;
        SEL lastSel = NULL;
        
        for (int i = 0; i < methodCount; i++) {
            
            Method method = methodList[i];
            NSString *methodName = [NSString stringWithCString:sel_getName(method_getName(method)) encoding:NSUTF8StringEncoding];
            if ([@"printIdentify" isEqualToString:methodName] ) {
                lastImp = method_getImplementation(method);
                lastSel = method_getName(method);
            }
        }
        
        typedef void (*fun) (id , SEL);
        if (lastImp != NULL) {
            fun f = (fun)lastImp;
            f(testCopy, lastSel);
//            使用下面的代码不可以，因为没有指向具体的函数
//            objc_msgSend(testCopy, lastSel);
        }
        
        free(methodList);
    }
    
    
    
}

//调用指定category中的方法, 需要知道category的加载顺序然后依次调用就可以了
- (void)callTheMethod:(NSInteger)index
{
    Class currentClass = [TestCopy class];
    TestCopy *instance = [[TestCopy alloc] init];

    
    if (currentClass) {
        
        unsigned int methodCount = 0;
        Method *methodList = class_copyMethodList(currentClass, &methodCount);
        
        IMP impArr[methodCount];
        SEL selArr[methodCount];
        
        IMP speciImp = NULL;
        SEL speciSel = NULL;
        
        int j = 0;
        for (int i = 0; i < methodCount; i++) {
            Method method = methodList[i];
            
            NSString *methodName = [NSString stringWithCString:sel_getName(method_getName(method)) encoding:NSUTF8StringEncoding];
            if ([@"printIdentify" isEqualToString:methodName]) {
                speciImp = method_getImplementation(method);
                speciSel = method_getName(method);
                
                impArr[j] = speciImp;
                selArr[j] = speciSel;
                j++;
            }
            
        }
        
        typedef void (* fun) (id, SEL);
        if (index < j) {
            speciImp = impArr[index];
            speciSel = selArr[index];
            fun f = (fun)speciImp;
            f(instance, speciSel);
        }
        
        free(methodList);
        
        
    }
    
}

- (void)getInstanceSize
{
    size_t classSize = class_getInstanceSize([TestCopy class]);
    NSLog(@"classSize:%zu",classSize);
    NSLog(@"sizeOfNSString:%lu",sizeof("NSString"));
    NSLog(@"sizeOfClass:%zu",sizeof("Class"));
    NSLog(@"sizeOfObject:%zu",sizeof("NSObject"));
    
    TestCopy *testCpy = [[TestCopy alloc] init];
    NSLog(@"ssss");
}

- (void)testStaticVariable
{
    for (int i = 0 ; i < 5; i++) {
        static NSString *identifier = @"identifier";
        NSLog(@"identifier:%@",identifier);
        
        static NSArray *arr;
        arr = [NSArray array];
        NSLog(@"arr:%@",arr);
        
    }
    
}

@end












